import java.util.ArrayList;

import static java.lang.System.out;

public final class NegaMax extends FixedDepth {

    public NegaMax(boolean isBlack, Eval evaluator, int searchDepth) {
        super(isBlack, evaluator, searchDepth);
    }

    @Override
    public Board findMove(Board board) {
	// IMPORTANT! If the player using findMove is White, then
	// the search method will be called with BLACK to move and
	// vice versa, i.e. THE RETURN VALUE FROM THE SEARCH-CALL WILL
	// REFLECT THE OPPONENTS BEST POSSIBLE SCORE
        assert board.blackToMove == isBlack;

        int bestValue = MIN;
        if (isBlack) {
            bestValue = MAX;
        }

        ArrayList<Board> moves = board.generateMoves();

	// If no moves found, return null as error flag
	if( moves.isEmpty() ) {
	    return null;
	}
	
	// If only one possible move found - just return that.
	if( moves.size() == 1 ) {
	    return moves.get(0);
	}

        Board bestMove = moves.get(0);
        if (moves.size() > 0) {
            bestMove = moves.get(0);
        }
        for (Board move : moves) {
            int value = search(move, searchDepth);
            if (isBlack) {
                if (value < bestValue) {
                    bestValue = value;
                    bestMove = move;
                }
            } else {
                if (-value > bestValue) {
                    bestValue = -value;
                    bestMove = move;
                }
	    }

        }

        if (bestMove != null && printBestMoveValue) {
            out.println("The best move has value " + bestValue);
        }

        return bestMove;
    }

    //    @Override
    public int search(Board board, int depthLeft) {

        // check for winnings
        if (    ((board.blackToMove) && (board.white == 0))
	     || ((!board.blackToMove) && (board.black == 0)) ) {
            return WHITE_WIN;
        }

        ArrayList<Board> moves = board.generateMoves();
        //if unable to move, this is a losing board for current player	
	//punish for depth left (embarrassing to lose with much depth left)
        if(moves.isEmpty()) {
            return WHITE_LOSS-depthLeft;
        }

        if(depthLeft == 0) {
            return evaluator.eval(board);
        }

        int bestValue = WHITE_LOSS;

        depthLeft--;
        for (Board move : moves) {
            int value = -search(move, depthLeft);
            if (value > bestValue) {
                bestValue = value;
            }
        }

        return bestValue;
    }
}
